// *****************************************************************************
// *****************************************************************************
// Copyright 2012 - 2019, Cadence Design Systems
//
// This  file  is  part  of  the  Cadence  LEF/DEF  Open   Source
// Distribution,  Product Version 5.8.
//
// Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
//    implied. See the License for the specific language governing
//    permissions and limitations under the License.
//
// For updates, support, or to become part of the LEF/DEF Community,
// check www.openeda.org for details.
//
//  $Author: dell $
//  $Revision: #1 $
//  $Date: 2020/09/29 $
//  $State:  $
// *****************************************************************************
// *****************************************************************************

#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <string>

#include "crypt.hpp"
#include "lefiDebug.hpp"
#include "lefiDefs.hpp"
#include "lefrCallBacks.hpp"
#include "lefrData.hpp"
#include "lefrReader.hpp"
#include "lefrSettings.hpp"
#include "lex.h"

#ifdef WIN32
#include <direct.h>
#else  // not WIN32
#include <unistd.h>
#endif  // WIN32

BEGIN_LEF_PARSER_NAMESPACE

#include "lef_parser.hpp"

extern YYSTYPE lefyylval;

inline std::string strip_case(const char* str)
{
  std::string result(str);

  if (lefData->namesCaseSensitive) {
    return result;
  };

  for (std::string::iterator p = result.begin(); result.end() != p; ++p) {
    *p = toupper(*p);
  }

  return result;
}

inline int lefGetKeyword(const char* name, int* result)
{
  std::map<const char*, int, lefCompareCStrings>::iterator search
      = lefSettings->Keyword_set.find(name);
  if (search != lefSettings->Keyword_set.end()) {
    *result = search->second;
    return true;
  }

  return false;
}

inline int lefGetStringDefine(const char* name, const char** value)
{
  std::map<std::string, std::string, lefCompareStrings>::iterator search
      = lefData->defines_set.find(strip_case(name));

  if (search != lefData->defines_set.end()) {
    *value = search->second.c_str();
    return true;
  }
  return false;
}

inline int lefGetIntDefine(const char* name, int* value)
{
  std::map<std::string, int, lefCompareStrings>::iterator search
      = lefData->defineb_set.find(strip_case(name));

  if (search != lefData->defineb_set.end()) {
    *value = search->second;
    return true;
  }
  return false;
}

inline int lefGetDoubleDefine(const char* name, double* value)
{
  std::map<std::string, double, lefCompareStrings>::iterator search
      = lefData->define_set.find(strip_case(name));

  if (search != lefData->define_set.end()) {
    *value = search->second;
    return true;
  }
  return false;
}

inline int lefGetAlias(const char* name, const char** value)
{
  std::map<std::string, std::string, lefCompareStrings>::iterator search
      = lefData->alias_set.find(strip_case(name));

  if (search != lefData->alias_set.end()) {
    *value = search->second.c_str();
    return true;
  }
  return false;
}

#define yyparse lefyyparse
#define yylex lefyylex
#define yyerror lefyyerror
#define yylval lefyylval
#define yychar lefyychar
#define yydebug lefyydebug
#define yynerrs lefyynerrs

// lef.cpph starts here.

// variable to count number of warnings

// 12/08/1999 -- Wanda da Rosa
// file pointer to the lefRWarning.log

extern char* lef_kywd(int num);

// User defined if log file should be in append from the previous run

// User defined if property string value should be process

// Varible from lex.cpph to keep track of invalid nonEnglish character
// in lef file

void lefReloadBuffer()
{
  int nb;

  nb = 0;

  if (lefData->first_buffer) {
    lefData->first_buffer = 0;
    if (lefSettings->ReadFunction) {
      if ((nb = (*lefSettings->ReadFunction)(
               lefData->lefrFile, lefData->current_buffer, 4))
          != 4) {
        lefData->next = nullptr;
        return;
      }
    } else {
      if ((nb = fread(lefData->current_buffer, 1, 4, lefData->lefrFile)) != 4) {
        lefData->next = nullptr;
        return;
      }
    }
    lefData->encrypted
        = encIsEncrypted((unsigned char*) lefData->current_buffer);
  }

  if (lefData->encrypted) {
    int i;
    int c;

    if (lefSettings->ReadEncrypted) {
      // is encrypted file and user has set the enable flag to read one
      for (i = 0; i < IN_BUF_SIZE; i++) {
        if ((c = encFgetc(lefData->lefrFile)) == EOF) {
          break;
        }
        lefData->current_buffer[i] = c;
      }
      nb = i;
    } else {  // an encrypted file, but user does not allow to read one
      printf("File is an encrypted file, reader is not set to read one.\n");
      return;
    }
  } else if (nb == 0) {
    if (lefSettings->ReadFunction) {
      nb = (*lefSettings->ReadFunction)(
          lefData->lefrFile, lefData->current_buffer, IN_BUF_SIZE);
    } else {
      // This is a normal file so just read some bytes.
      nb = fread(lefData->current_buffer, 1, IN_BUF_SIZE, lefData->lefrFile);
    }
  }

  if (nb <= 0) {
    lefData->next = nullptr;
  } else {
    lefData->next = lefData->current_buffer;
    lefData->last = lefData->current_buffer + nb - 1;
  }
}

int lefGetc()
{
  if (lefData->input_level >= 0) {  // Token has been getting from
    const char *ch, *s;
    s = ch = lefData->current_stack[lefData->input_level];
    lefData->current_stack[lefData->input_level] = ++s;
    return *ch;
  }

  // Remove '\r' symbols from Windows streams.
  for (;;) {
    if (lefData->next > lefData->last) {
      lefReloadBuffer();
    }
    if (lefData->next == nullptr) {
      return EOF;
    }

    int ch = static_cast<unsigned char>(*lefData->next++);

    if (ch != '\r') {
      return ch;
    }
  }
}

void UNlefGetc(char ch)
{
  if ((lefData->next <= lefData->current_buffer)
      || (lefData->input_level > 0)) {
    lefError(1111, "UNlefGetc: buffer access violation.");
  } else {
    *(--lefData->next) = ch;
  }
}

// The following two variables are for communicating with the parser
/* Return a copy of the string allocated from the lefData->ring buffer.
 * We will keep several strings in the buffer and just reuse them.
 * This could cause problems if we need to use more strings than we
 * have in the buffer.
 */
static char* ringCopy(const char* string)
{
  int len = strlen(string) + 1;
  if (++lefData->ringPlace >= RING_SIZE) {
    lefData->ringPlace = 0;
  }
  if (len > lefData->ringSizes[lefData->ringPlace]) {
    lefData->ring[lefData->ringPlace]
        = (char*) lefRealloc(lefData->ring[lefData->ringPlace], len);
    lefData->ringSizes[lefData->ringPlace] = len;
  }
  strcpy(lefData->ring[lefData->ringPlace], string);
  return lefData->ring[lefData->ringPlace];
}

char* qStrCopy(char* string)
{
  int len = strlen(string) + 3;
  char* retStr;

  retStr = (char*) lefMalloc(len);
  sprintf(retStr, "\"%s\"", string);
  return retStr;
}

/* NOTE: we don't allocate these tables until they are used.  The reason
 * we don't allocate at the beginning of the program is that we don't know
 * at that point if we should be case sensitive or not. */

void lefAddStringDefine(const char* token, const char* str)
{
  std::string tmpStr((lefData->lefDefIf == true) ? "" : "\"");

  tmpStr += str;

  lefData->defines_set[strip_case(token)] = tmpStr;
  lefData->lefDefIf = false;
  lefData->inDefine = 0;
}

void lefAddBooleanDefine(const char* token, int val)
{
  lefData->defineb_set[strip_case(token)] = val;
}

void lefAddNumDefine(const char* token, double val)
{
  lefData->define_set[strip_case(token)] = val;
}

static int GetTokenFromStack(char* s)
{
  const char* ch;       // utility variable
  char* prS = nullptr;  // pointing to the previous char or s
  char* save = s;       // for debug printing

  while (lefData->input_level >= 0) {
    for (ch = lefData->current_stack[lefData->input_level]; *ch != 0;
         ch++) {  // skip white space
      if (*ch != ' ' && *ch != '\t' && (lefData->lefNlToken || *ch != '\n')) {
        break;
      }
    }
    // did we find anything?  If not, decrement level and try again
    if (*ch == 0) {
      lefData->input_level--;
    } else if (*ch == '\n') {
      *s++ = *ch;
      *s = 0;
      if (lefData->lefDebug[11]) {
        printf("Stack[%d] Newline token\n", lefData->input_level);
      }
      return true;
    } else {  // we found something
      for (;; ch++) {
        if (*ch == ' ' || *ch == '\t' || *ch == '\n' || *ch == 0) {
          /* 10/10/2000 - Wanda da Rosa, pcr 341032
          ** Take out the lefData->last '"', the 1st will be skip later
          */
          if (*prS == '"') {
            *prS = '\0';
          } else {
            *s++ = '\0';
          }
          lefData->current_stack[lefData->input_level] = ch;
          if (lefData->lefDebug[11]) {
            printf("Stack[%d]: <%s>, dm=%d\n",
                   lefData->input_level,
                   save,
                   lefData->lefDumbMode);
          }
          return true;
        }
        /* 10/10/2000 - Wanda da Rosa, pcr 341032
        ** Save the location of the previous s
        */
        prS = s;
        *s++ = *ch;
      }
    }
  }
  return false;  // if we get here, we ran out of input levels
}

// Increment current position of buffer pointer.
// Double buffer size if curPos is out of boundary.
static inline void IncCurPos(char** curPos, char** buffer, int* bufferSize)
{
  (*curPos)++;
  if (*curPos - *buffer < *bufferSize) {
    return;
  }

  long offset = *curPos - *buffer;

  *bufferSize *= 2;
  *buffer = (char*) realloc(*buffer, *bufferSize);
  *curPos = *buffer + offset;
}

inline static void print_nlines(int lineNum)
{
  // call the callback line number function if it is set
  if (lefSettings->LineNumberFunction
      && (lineNum % lefSettings->DeltaNumberLines) == 0) {
    lefSettings->LineNumberFunction(lineNum);
  }
}

static int GetToken(char** buffer, int* bufferSize)
{
  char* s = *buffer;
  int ch;

  lefData->lef_ntokens++;
  lefData->lefInvalidChar = 0;

  if (lefData->input_level >= 0) {  // if we are expanding an alias
    if (GetTokenFromStack(s)) {     // try to get a token from it
      return true;                  // if we get one, return it
    }
  }  // but if not, continue

  // skip blanks and count lines
  while ((ch = lefGetc()) != EOF) {
    // check if the file is encrypted and user allows to read
    if (lefData->encrypted && !lefSettings->ReadEncrypted) {
      ch = EOF;
    }
    if (ch == '\n') {
      print_nlines(++lefData->lef_nlines);
    }
    if (ch != ' ' && ch != '\t' && (lefData->lefNlToken || ch != '\n')) {
      break;
    }
  }

  if (ch == EOF) {
    return false;
  }

  if (ch == '\n') {
    *s = ch;
    IncCurPos(&s, buffer, bufferSize);

    *s = '\0';
    if (lefData->lefDebug[11]) {
      printf("Newline token\n");
    }
    return true;
  }

  // now get the token
  if (ch == '"') {
    do {
      /* 5/6/2008 - CCR 556818
      ** Check if the ch is a valid ascii character 0 =< ch < 128
      ** If not write out an error
      */
      /* 8/7/2008 - CCR 586175
      ** Some files may not end with \n or \0 or EOF as the lefData->last
      *character
      ** The parser allows this char instead of error out
      */
      if ((ch < -1) || (ch > 127)) {
        lefData->lefInvalidChar = 1;
      }

      /* 8/22/2000 - Wanda da Rosa, pcr 333334
      ** save the previous char to allow backslash quote within quote
      */
      if (!lefSettings->DisPropStrProcess) {
        // 3/4/2008 - CCR 523879 - convert \\ to \, \" to ", \x to x
        if (ch == '\\') {  // got a \, save the lefData->next char only
          ch = lefGetc();

          if ((ch == '\n') || (ch == EOF)) {
            *s = '\0';
            lefError(6015, "Unexpected end of the LEF file.");
            lefData->hasFatalError = 1;
            return false;
          }
        }
      }

      // 5/5/2004 - pcr 704784
      // If name, or quote string is longer than current buffer size
      // increase the buffer.
      *s = ch;
      IncCurPos(&s, buffer, bufferSize);

      ch = lefGetc();

      // 7/23/2003 - pcr 606558 - do not allow \n in a string instead
      // of ;
      if (ch == '\n') {
        print_nlines(++lefData->lef_nlines);
        // 2/2/2007 - PCR 909714, allow string to go more than 1 line
        //            continue to parse
      }

      if (ch == EOF) {
        *s = '\0';
        lefError(6015, "Unexpected end of the LEF file.");
        lefData->hasFatalError = 1;
        return false;
      }
    } while (ch != '"');
    *s = '\0';
    /* 10/31/2006 - pcr 926068
    ** When it reaches to here, chances are it reaches the end ".
    ** Check if there is a space following the "
    */
    if (ch == '"') {
      ch = lefGetc();
      if (ch != ' ' && ch != EOF) {
        UNlefGetc(ch);
        lefData->spaceMissing = 1;
        return false;
      }
      UNlefGetc(ch);
    }
    return true;
  }

  if (lefData->namesCaseSensitive) {
    for (;; ch = lefGetc()) {
      /* 5/6/2008 - CCR 556818
      ** Check if the ch is a valid ascii character 0 =< ch < 128
      ** If not write out an error
      */
      if ((ch < -1) || (ch > 127)) {
        lefData->lefInvalidChar = 1;
      }

      if (ch == ' ' || ch == '\t' || ch == '\n' || ch == EOF) {
        break;
      }

      *s = ch;
      IncCurPos(&s, buffer, bufferSize);
    }
  } else if (lefSettings->ShiftCase) {  // we are case insensitive, use a
                                        // different loop
    for (;; ch = lefGetc()) {
      /* 5/6/2008 - CCR 556818
      ** Check if the ch is a valid ascii character 0 =< ch < 128
      ** If not write out an error
      */
      if ((ch < -1) || (ch > 127)) {
        lefData->lefInvalidChar = 1;
      }

      if (ch == ' ' || ch == '\t' || ch == '\n' || ch == EOF) {
        break;
      }

      *s = (ch >= 'a' && ch <= 'z') ? (ch - 'a' + 'A') : ch;
      IncCurPos(&s, buffer, bufferSize);
    }
  } else {
    for (;; ch = lefGetc()) {
      /* 5/6/2008 - CCR 556818
      ** Check if the ch is a valid ascii character 0 =< ch < 128
      ** If not write out an error
      */
      if ((ch < -1) || (ch > 127)) {
        lefData->lefInvalidChar = 1;
      }

      if (ch == ' ' || ch == '\t' || ch == '\n' || ch == EOF) {
        break;
      }

      *s = ch;
      IncCurPos(&s, buffer, bufferSize);
    }
  }

  // If we got this far, the lefData->last char was whitespace
  *s = '\0';
  if (ch != EOF) {  // shouldn't ungetc an EOF
    UNlefGetc(ch);
  }
  return true;
}

// creates an upper case copy of an array
void lefuc_array(char* source, char* dest)
{
  for (; *source != 0;) {
    *dest++ = toupper(*source++);
  }
  *dest = 0;
}

void lefStoreAlias()
{
  std::string so_far;  // contains alias contents as we build it

  int tokenSize = 10240;
  char* aname = (char*) malloc(tokenSize);

  GetToken(&aname, &tokenSize);

  char* line = (char*) malloc(tokenSize);

  GetToken(&line, &tokenSize);  // should be "="

  char* uc_line = (char*) malloc(tokenSize);

  if (strcmp(line, "=") != 0) {
    lefError(1000, "Expecting '='");
  }

  /* now keep getting lines till we get one that contains &ENDALIAS */
  for (char* p = nullptr; p == nullptr;) {
    int i;
    char* s = line;
    for (i = 0; i < tokenSize - 1; i++) {
      int ch = lefGetc();
      if (ch == EOF) {
        lefError(1001, "End of file in &ALIAS");
        return;
      }

      *s++ = ch;

      if (ch == '\n') {
        print_nlines(++lefData->lef_nlines);
        break;
      }
    }

    *s = '\0';
    lefuc_array(line, uc_line);        // make upper case copy
    p = strstr(uc_line, "&ENDALIAS");  // look for END_ALIAS

    if (p != nullptr) {             // if we find it
      *(line + (p - uc_line)) = 0;  // remove it from the line
    }

    so_far += line;
  }

  char* dup = (char*) malloc(strlen(so_far.c_str()) + 1);

  strcpy(dup, so_far.c_str());
  lefData->alias_set[strip_case(aname)] = dup;

  free(aname);
  free(line);
  free(uc_line);
}

int lefamper_lookup(char* token);  // forward reference to this routine

/* The main routine called by the YACC parser to get the lefData->next token.
 *    Returns 0 if no more tokens are available.
 *    Returns an integer for keywords (see the yacc_defines.h for values)
 *    Returns the character itself for punctuation
 *    Returns NUMBER for numeric looking tokens
 *    Returns T_STRING for anything else
 * If the global "lefData->lefDumbMode" is > 0, it reads the lefData->next token
 * in "dumb mode". In this case, it does not do keyword lookup, or attempt to
 * read a token as a number; if the token is not punctuation, it's a T_STRING.
 * Each token read decrements lefData->lefDumbMode, so you can instruct the the
 * lexer to read the lefData->next N tokens in dumb mode by setting
 * "lefData->lefDumbMode" to that value.
 *
 * Newlines are in general silently ignored.  If the global lefData->lefNlToken
 * is true, however, they are returned as the token K_NL.
 */
extern int lefsublex();

int yylex()
{
  int v = lefsublex();

  if (lefData->lefDebug[13]) {
    if (v == 0) {
      printf("yylex NIL\n");
    } else if (v < 256) {
      printf("yylex char %c\n", v);
    } else if (v == QSTRING) {
      printf("yylex quoted string '%s'\n", yylval.string);
    } else if (v == T_STRING) {
      printf("yylex string '%s'\n", yylval.string);
    } else if (v == NUMBER) {
      printf("yylex number %f\n", yylval.dval);
    } else {
      printf("yylex keyword %s\n", lef_kywd(v));
    }
  }

  // At 5.6, lefData->doneLib is always true, since "END LIBRARY" is optional
  if ((v == 0) && (!lefData->doneLib)) {
    if (!lefData->spaceMissing) {
      lefError(1002, "Incomplete lef file.");
      lefData->hasFatalError = 1;
    }

    return (-1);
  }

  return v;
}

int lefsublex()
{
  char fc;
  char* outStr;

  strcpy(lefData->pv_token, lefData->current_token);  // save the previous token

  /* First, we eat all the things the parser should be unaware of.
   * This includes:
   * a) Comments
   * b) &alias definitions
   * c) &alias expansions
   */

  for (;;) {
    if (!GetToken(&lefData->current_token,
                  &lefData->tokenSize)) {  // get a raw token
      return 0;
    }

    // Token size can change. Do preventive re-alloc.
    char* new_uc_token = (char*) realloc(lefData->uc_token, lefData->tokenSize);
    if (!new_uc_token) {
      throw std::bad_alloc();
    }
    lefData->uc_token = new_uc_token;

    char* new_pv_token = (char*) realloc(lefData->pv_token, lefData->tokenSize);
    if (!new_pv_token) {
      throw std::bad_alloc();
    }
    lefData->pv_token = new_pv_token;

    fc = lefData->current_token[0];

    /* lefData->first, check for comments or &alias statements.  Comments we
     * ignore, and &alias statements are eaten and recorded by the lexer.
     */
    if (fc == lefSettings->CommentChar) {
      for (fc = lefGetc();; fc = lefGetc()) {  // so skip to the end of line
        if (fc == EOF) {
          return 0;
        }
        if (fc == '\n') {
          print_nlines(++lefData->lef_nlines);
          break;
        }
      }
    } else if (fc == '&') {
      // begins with &.  If &alias, read contents and
      // store them.  Otherwise it's a define, or a macro use.
      const char* cptr;
      lefuc_array(lefData->current_token, lefData->uc_token);
      if (strcmp(lefData->uc_token, "&ALIAS") == 0) {
        lefStoreAlias();  // read and store the alias
      } else if (strncmp(lefData->uc_token, "&DEFINE", 7) == 0) {
        lefData->inDefine = 1;  // it is a define statement
        break;
      } else if (lefGetAlias(lefData->current_token, &cptr)) {
        lefData->current_stack[++lefData->input_level] = cptr;
      } else if (lefGetStringDefine(lefData->current_token, &cptr)
                 && !lefData->inDefine) {
        lefData->current_stack[++lefData->input_level] = cptr;
      } else {
        break;  // begins with &, but not an &alias defn. or use.
      }
    } else {
      break;  // does not begin with CommentChar or '&'
    }
  }

  if (lefData->lefInvalidChar) {
    outStr = (char*) lefMalloc(500 + strlen(lefData->current_token));
    sprintf(outStr,
            "Invalid characters found in \'%s\'.\nThese characters might have "
            "created by character types other than English.",
            lefData->current_token);
    lefError(1008, outStr);
    lefFree(outStr);
    return 0;
  }

  if (lefData->ge56almostDone
      && (strcmp(lefData->current_token, "END") == 0
          || strcmp(lefData->current_token, "BEGINEXT") == 0)) {
    // Library has BEGINEXT and also end with END LIBRARY
    // Use END LIBRARY to indicate the end of the library
    lefData->ge56almostDone = 0;
  }

  if ((lefData->doneLib && lefData->versionNum < 5.6)
      ||  // END LIBRARY is passed for pre 5.6
      ((lefData->ge56almostDone && strcmp(lefData->current_token, "END")
        && strcmp(lefData->current_token, "BEGINEXT"))
       ||                     // after EXT, not follow by END
       lefData->ge56done)) {  // END LIBRARY is passed for >= 5.6
    fc = EOF;
    lefInfo(3000, "There are still data after the END LIBRARY");
    return 0;
  }

  if (fc == '\"') {
    yylval.string = ringCopy(&(lefData->current_token[1]));
    return QSTRING;
  }

  // at this point we've read a token
  // printf("Token is %s\n", token);
  lefData->lefDumbMode--;
  lefData->lefNoNum--;
  if (isdigit(fc) || fc == '.'
      || (fc == '-' && lefData->current_token[1] != '\0')) {
    char* ch;
    yylval.dval = strtod(lefData->current_token, &ch);
    if (lefData->lefNoNum < 0 && *ch == '\0') {  // did we use the whole string?
      return NUMBER;
    }
    // failed integer conversion, try floating point
    yylval.string = ringCopy(lefData->current_token);  // NO, it's a string
    return T_STRING;
  }

  // 5/17/2004 - Special checking for nondefaultrule
  if (lefData->lefNdRule && (strcmp(lefData->current_token, "END") != 0)) {
    if (strcmp(lefData->current_token, lefData->ndName) == 0) {
      yylval.string = ringCopy(lefData->current_token);  // a nd rule name
      return T_STRING;
    }
    // Can be NONDEFAULTRULE END without name, this case, string
    // should be a reserve word  or name is incorrect
    // lefData->first check if it is a reserve word
    lefData->lefDumbMode = -1;
  }
  // if we are dumb mode, all we return is punctuation and strings & numbers
  // until we see the lefData->next '+' or ';' token
  if (lefData->lefDumbMode >= 0) {
    if (lefData->current_token[1] == '\0'
        && (fc == '(' || fc == ')' || fc == '+' || fc == ';' || fc == '*')) {
      if (fc == ';' || fc == '+') {
        lefData->lefDumbMode = 0;
      }
      return (int) fc;
    }
    if (lefData->lefNewIsKeyword
        && strcmp(lefData->current_token, "NEW") == 0) {
      return K_NEW;  // even in dumb mode, we must see the NEW token
    }
    yylval.string = ringCopy(lefData->current_token);
    // 5/17/2004 - Special checking for nondefaultrule
    if (lefData->lefNdRule) {
      if (strcmp(lefData->current_token, lefData->ndName) == 0) {
        return T_STRING;
      }
      // Can be NONDEFAULTRULE END without name, this case, string
      // should be a reserve word  or name is incorrect
      // lefData->first check if it is a reserve word
    }
    return T_STRING;
  }

  // if we get here we are in smart mode.  Parse token
  if (isalpha(fc) || fc == '&' || fc == '_') {
    int result;
    char *ch, *uch;

    for (ch = lefData->current_token, uch = lefData->uc_token; *ch != '\0';
         ch++) {
      *uch++ = toupper(*ch);
    }
    *uch = '\0';

    lefData->Hist_text.resize(0);

    if (lefGetKeyword(lefData->uc_token, &result)) {
      if (K_HISTORY == result) {  // history - get up to ';'
        int c;
        int prev;
        prev = ' ';
        for (;;) {
          c = lefGetc();

          if (c == EOF) {
            lefError(6015, "Unexpected end of the LEF file.");
            lefData->hasFatalError = 1;
            break;
          }

          if (c == ';' && (prev == ' ' || prev == '\t' || prev == '\n')) {
            break;
          }
          if (c == '\n') {
            // call the callback line number function if it is set
            print_nlines(++lefData->lef_nlines);
          }
          prev = c;
          lefData->Hist_text.push_back(c);
        }
        lefData->Hist_text.push_back('\0');
      } else if (K_BEGINEXT == result) {  // extension, get up to end
        int cc;
        int foundTag = 0;
        int notEmpTag = 0;
        int begQuote = 0;
        // First make sure there is a name after BEGINEXT within quote
        // BEGINEXT "name"
        for (cc = lefGetc();; cc = lefGetc()) {
          if (cc == EOF) {
            break;  // lef file may not have END LIB
          }
          if (cc == '\n') {
            if (!foundTag) {
              lefError(1003, "tag is missing for BEGINEXT");
              break;
            }
          } else {
            // Make sure the tag is quoted
            lefData->Hist_text.push_back(cc);
            if (cc != ' ') {
              if (cc == '\"') {  // found a quote
                if (!begQuote) {
                  begQuote = 1;
                } else if (notEmpTag) {
                  foundTag = 1;
                  break;  // Found the quoted tag
                } else {
                  lefError(1004, "Tag for BEGINEXT is empty");
                  break;
                }
              } else if (!begQuote) {  // anything but a quote
                lefError(1005, "\" is missing in tag");
                break;
              } else {          // anything but a quote and there
                notEmpTag = 1;  // is already a quote
              }
            }
          }
        }
        if (foundTag) {
          // We have handle with the tag, just read the rest until
          // ENDEXT
          begQuote = 0;
          for (cc = lefGetc();; cc = lefGetc()) {
            if (cc == EOF) {
              break;  // lef file may not have END LIB
            }
            if (cc == '\n') {
              // call the callback line number function if it is set
              print_nlines(++lefData->lef_nlines);
            } else if (cc == '\"') {
              if (!begQuote) {
                begQuote = 1;
              } else {
                begQuote = 0;
              }
            }
            lefData->Hist_text.push_back(cc);
            int histTextSize = lefData->Hist_text.size();

            if (histTextSize >= 6
                && memcmp(&lefData->Hist_text[histTextSize - 6], "ENDEXT", 6)
                       == 0) {
              if (begQuote) {
                lefError(1006, "Ending \" is missing");
              }
              break;
            }
            if (histTextSize >= 11
                && memcmp(&lefData->Hist_text[histTextSize - 11],
                          "END LIBRARY",
                          11)
                       == 0) {
              lefError(1007, "ENDEXT is missing");
              return 1;
            }
          }
        }
        lefData->Hist_text.push_back('\0');
      }
      return result;  // YES, return its value
    }
    if (fc == '&') {
      return lefamper_lookup(lefData->current_token);
    }
    yylval.string = ringCopy(lefData->current_token);  // NO, it's a string
    return T_STRING;
  }
  // it should be a punctuation character
  if (lefData->current_token[1] != '\0') {
    if (strcmp(lefData->current_token, ">=") == 0) {
      return K_GE;
    }
    if (strcmp(lefData->current_token, "<=") == 0) {
      return K_LE;
    }
    if (strcmp(lefData->current_token, "<>") == 0) {
      return K_NE;
    }
    if (lefData->current_token[0]
        == ';') {  // we got ';TOKEN' which is not allowed by
      //';' cannot be attached to other tokens.
      lefError(1009, "Symbol ';' should be separated by space(s).");
      return 0;
      // strcpy(saved_token, &token[1]); // the standard syntax, but
      // stack[++lefData->input_level] = saved_token; // C3 and GE support.
    }
    if (lefData->current_token[0]
        == '_') {  // name starts with _, return as T_STRING
      yylval.string = ringCopy(lefData->current_token);
      return T_STRING;
    }
    lefError(6016, "Odd punctuation found.");
    lefData->hasFatalError = 1;
    return 0;
  }
  if (strlen(lefData->current_token) > 2
      || strlen(lefData->current_token) == 0) {
    lefError(6016, "Odd punctuation found.");
    lefData->hasFatalError = 1;
    return 0;
  }
  return (int) lefData->current_token[0];
}

/* We have found a token beginning with '&'.  If it has been previously
   defined, substitute the definition.  Otherwise return it. */
int lefamper_lookup(char* token)
{
  double dptr;
  int result;
  const char* cptr;

  // printf("Amper_lookup: %s\n", token);

  // &define returns a number
  if (lefGetDoubleDefine(token, &dptr)) {
    yylval.dval = dptr;
    return NUMBER;
  }
  // &defineb returns true or false, encoded as K_TRUE or K_FALSE
  if (lefGetIntDefine(token, &result)) {
    return result;
  }
  // &defines returns a T_STRING
  if (lefGetStringDefine(token, &cptr)) {
    if (lefGetKeyword(cptr, &result)) {
      return result;
    }
    yylval.string = ringCopy(cptr);
    return (cptr[0] == '\"' ? QSTRING : T_STRING);
  }
  // if none of the above, just return the token.
  yylval.string = ringCopy(token);
  return T_STRING;
}

void lefError(int msgNum, const char* s)
{
  char* str;
  const char* curToken = isgraph(lefData->current_token[0])
                             ? lefData->current_token
                             : "<unprintable>";
  const char* pvToken
      = isgraph(lefData->pv_token[0]) ? lefData->pv_token : "<unprintable>";
  int len = strlen(curToken) - 1;
  int pvLen = strlen(pvToken) - 1;

  if (lefData->hasFatalError) {
    return;
  }
  if ((lefSettings->TotalMsgLimit > 0)
      && (lefData->lefErrMsgPrinted >= lefSettings->TotalMsgLimit)) {
    return;
  }
  if (lefSettings->MsgLimit[msgNum] > 0) {
    if (lefData->msgLimit[0][msgNum]
        >= lefSettings->MsgLimit[msgNum]) {  // over the limit
      return;
    }
    lefData->msgLimit[0][msgNum] = lefData->msgLimit[0][msgNum] + 1;
  }

  // PCR 690679, probably missing space before a ';'
  if (strcmp(s, "parse error") == 0) {
    if ((len > 1) && (lefData->current_token[len] == ';')) {
      str = (char*) lefMalloc(len + strlen(s) + strlen(lefData->lefrFileName)
                              + 350);
      sprintf(str,
              "ERROR (LEFPARS-%d): %s, see file %s at line %d\nLast token was "
              "<%s>, space is missing before <;>\n",
              msgNum,
              s,
              lefData->lefrFileName,
              lefData->lef_nlines,
              curToken);
    } else if ((pvLen > 1) && (lefData->pv_token[pvLen] == ';')) {
      str = (char*) lefMalloc(pvLen + strlen(s) + strlen(lefData->lefrFileName)
                              + 350);
      sprintf(str,
              "ERROR (LEFPARS-%d): %s, see file %s at line %d\nLast token was "
              "<%s>, space is missing before <;>\n",
              msgNum,
              s,
              lefData->lefrFileName,
              lefData->lef_nlines - 1,
              pvToken);
    } else if ((lefData->current_token[0] == '"') && (lefData->spaceMissing)) {
      // most likely space is missing after the end "
      str = (char*) lefMalloc(len + strlen(s) + strlen(lefData->lefrFileName)
                              + 350);
      sprintf(str,
              "ERROR (LEFPARS-%d): %s, see file %s at line %d\nLast token was "
              "<%s\">, space is missing between the closing \" of the string "
              "and ;.\n",
              1010,
              s,
              lefData->lefrFileName,
              lefData->lef_nlines,
              curToken);
      lefData->spaceMissing = 0;
    } else {
      str = (char*) lefMalloc(len + strlen(lefData->lefrFileName) + 350);
      sprintf(str,
              "ERROR (LEFPARS-%d): Lef parser has encountered an error in file "
              "%s at line %d, on token %s.\nProblem can be syntax error on the "
              "lef file or an invalid parameter name.\nDouble check the syntax "
              "on the lef file with the LEFDEF Reference Manual.\n",
              msgNum,
              lefData->lefrFileName,
              lefData->lef_nlines,
              curToken);
    }
  } else if (strcmp(s, "syntax error") == 0) {  // linux machines
    if ((len > 1) && (lefData->current_token[len] == ';')) {
      str = (char*) lefMalloc(len + strlen(s) + strlen(lefData->lefrFileName)
                              + 350);
      sprintf(str,
              "ERROR (LEFPARS-%d): %s, see file %s at line %d\nLast token was "
              "<%s>, space is missing before <;>\n",
              msgNum,
              s,
              lefData->lefrFileName,
              lefData->lef_nlines,
              curToken);
    } else if ((pvLen > 1) && (lefData->pv_token[pvLen] == ';')) {
      str = (char*) lefMalloc(pvLen + strlen(s) + strlen(lefData->lefrFileName)
                              + 350);
      sprintf(str,
              "ERROR (LEFPARS-%d): %s, see file %s at line %d\nLast token was "
              "<%s>, space is missing before <;>\n",
              msgNum,
              s,
              lefData->lefrFileName,
              lefData->lef_nlines - 1,
              pvToken);
    } else if ((lefData->current_token[0] == '"') && (lefData->spaceMissing)) {
      // most likely space is missing after the end "
      str = (char*) lefMalloc(len + strlen(s) + strlen(lefData->lefrFileName)
                              + 350);
      sprintf(str,
              "ERROR (LEFPARS-%d): %s, see file %s at line %d\nLast token was "
              "<%s\">, space is missing between the closing \" of the string "
              "and ;.\n",
              1011,
              s,
              lefData->lefrFileName,
              lefData->lef_nlines,
              curToken);
      lefData->spaceMissing = 0;
    } else {
      str = (char*) lefMalloc(len + strlen(lefData->lefrFileName) + 350);
      sprintf(str,
              "ERROR (LEFPARS-%d): Lef parser has encountered an error in file "
              "%s at line %d, on token %s.\nProblem can be syntax error on the "
              "lef file or an invalid parameter name.\nDouble check the syntax "
              "on the lef file with the LEFDEF Reference Manual.\n",
              msgNum,
              lefData->lefrFileName,
              lefData->lef_nlines,
              curToken);
    }
  } else {
    str = (char*) lefMalloc(len + strlen(s) + strlen(lefData->lefrFileName)
                            + 350);
    sprintf(
        str,
        "ERROR (LEFPARS-%d): %s Error in file %s at line %d, on token %s.\n",
        msgNum,
        s,
        lefData->lefrFileName,
        lefData->lef_nlines,
        curToken);
  }
  fflush(stdout);
  lefiError(1, msgNum, str);
  free(str);
  lefData->lefErrMsgPrinted++;
  // Not really error, error numbers between 1300 & 1499, those errors
  // are not from lef.y or the parser
  if ((msgNum < 1300) || (msgNum > 1499)) {
    lefData->lef_errors++;
  }
}

// yyerror is called by bison.simple, 5 locations will call this function
void yyerror(const char* s)
{
  lefError(lefData->msgCnt++, s);
}

// All info starts with 3000
// All info within lefInfo starts with 3500
void lefInfo(int msgNum, const char* s)
{
  int disableStatus = lefSettings->suppresMsg(msgNum);

  if (disableStatus == 1) {
    char msgStr[60];
    sprintf(msgStr,
            "Message (LEFPARS-%d) has been suppressed from output.",
            msgNum);
    lefWarning(2502, msgStr);
    return;
  }
  if (disableStatus == 2) {
    return;
  }

  if ((lefSettings->TotalMsgLimit > 0)
      && (lefData->lefInfoMsgPrinted >= lefSettings->TotalMsgLimit)) {
    return;
  }
  if (lefSettings->MsgLimit[msgNum] > 0) {
    if (lefData->msgLimit[0][msgNum]
        >= lefSettings->MsgLimit[msgNum]) {  // over the limit
      char msgStr[100];
      if (lefData->msgLimit[1][msgNum]) {  // already printed out warning
        return;
      }
      lefData->msgLimit[1][msgNum] = 1;
      sprintf(
          msgStr,
          "Message (LEFPARS-%d) has exceeded the message display limit of %d",
          msgNum,
          lefSettings->MsgLimit[msgNum]);
      lefWarning(2503, msgStr);
      return;
    }
    lefData->msgLimit[0][msgNum] = lefData->msgLimit[0][msgNum] + 1;
  }
  lefData->lefInfoMsgPrinted++;

  if (lefSettings->WarningLogFunction) {
    char* str = (char*) lefMalloc(strlen(lefData->current_token) + strlen(s)
                                  + strlen(lefData->lefrFileName) + 350);
    sprintf(str,
            "INFO (LEFPARS-%d): %s See file %s at line %d.\n",
            msgNum,
            s,
            lefData->lefrFileName,
            lefData->lef_nlines);
    (*lefSettings->WarningLogFunction)(str);
    free(str);
  } else if (lefData->lefrLog) {
    fprintf(lefData->lefrLog,
            "INFO (LEFPARS-%d): %s See file %s at line %d\n",
            msgNum,
            s,
            lefData->lefrFileName,
            lefData->lef_nlines);
  } else {
    if (!lefData->hasOpenedLogFile) {
      if ((lefData->lefrLog = fopen("lefRWarning.log", "w")) == nullptr) {
        printf(
            "WARNING (LEFPARS-3500): Unable to open the file lefRWarning.log "
            "in %s.\n",
            getcwd(nullptr, 64));
        printf("Info messages will not be printed.\n");
      } else {
        lefData->hasOpenedLogFile = 1;
        fprintf(
            lefData->lefrLog, "Info from file: %s\n\n", lefData->lefrFileName);
        fprintf(lefData->lefrLog,
                "INFO (LEFPARS-%d): %s See file %s at line %d\n",
                msgNum,
                s,
                lefData->lefrFileName,
                lefData->lef_nlines);
      }
    } else {
      if ((lefData->lefrLog = fopen("lefRWarning.log", "a")) == nullptr) {
        printf(
            "WARNING (LEFPARS-3500): Unable to open the file lefRWarning.log "
            "in %s.\n",
            getcwd(nullptr, 64));
        printf("Info messages will not be printed.\n");
      } else {
        fprintf(lefData->lefrLog,
                "\nInfo from file: %s\n\n",
                lefData->lefrFileName);
        fprintf(lefData->lefrLog,
                "INFO (LEFPARS-%d): %s See file %s at line %d\n",
                msgNum,
                s,
                lefData->lefrFileName,
                lefData->lef_nlines);
      }
    }
  }
}

// All warning starts with 2000
// All warning within lefWarning starts with 2500
void lefWarning(int msgNum, const char* s)
{
  if (lefSettings->dAllMsgs) {  // all messages are suppressed
    return;
  }

  if ((msgNum != 2502) && (msgNum != 2503)) {
    int disableStatus = lefSettings->suppresMsg(msgNum);

    if (disableStatus == 1) {
      char msgStr[60];
      sprintf(msgStr,
              "Message (LEFPARS-%d) has been suppressed from output.",
              msgNum);
      lefWarning(2502, msgStr);
      return;
    }
    if (disableStatus == 2) {
      return;
    }
  }

  if ((lefSettings->TotalMsgLimit > 0)
      && (lefData->lefWarnMsgPrinted >= lefSettings->TotalMsgLimit)) {
    return;
  }
  if (lefSettings->MsgLimit[msgNum] > 0) {
    if (lefData->msgLimit[0][msgNum]
        >= lefSettings->MsgLimit[msgNum]) {  // over the limit
      char msgStr[100];
      if (lefData->msgLimit[1][msgNum]) {  // already printed out warning
        return;
      }
      lefData->msgLimit[1][msgNum] = 1;
      sprintf(
          msgStr,
          "Message (LEFPARS-%d) has exceeded the message display limit of %d",
          msgNum,
          lefSettings->MsgLimit[msgNum]);
      lefWarning(2503, msgStr);
      return;
    }
    lefData->msgLimit[0][msgNum] = lefData->msgLimit[0][msgNum] + 1;
  }
  lefData->lefWarnMsgPrinted++;

  if (lefSettings->WarningLogFunction) {
    char* str = (char*) lefMalloc(strlen(lefData->current_token) + strlen(s)
                                  + strlen(lefData->lefrFileName) + 350);
    sprintf(str,
            "WARNING (LEFPARS-%d): %s See file %s at line %d.\n",
            msgNum,
            s,
            lefData->lefrFileName,
            lefData->lef_nlines);
    (*lefSettings->WarningLogFunction)(str);
    free(str);
  } else if (lefData->lefrLog) {
    fprintf(lefData->lefrLog,
            "WARNING (LEFPARS-%d): %s See file %s at line %d\n",
            msgNum,
            s,
            lefData->lefrFileName,
            lefData->lef_nlines);
  } else {
    if (!lefData->hasOpenedLogFile) {
      if ((lefData->lefrLog = fopen("lefRWarning.log", "w")) == nullptr) {
        printf(
            "WARNING (LEFPARS-2500): Unable to open the file lefRWarning.log "
            "in %s.\n",
            getcwd(nullptr, 64));
        printf("Warning messages will not be printed.\n");
      } else {
        lefData->hasOpenedLogFile = 1;
        fprintf(lefData->lefrLog,
                "Warnings from file: %s\n\n",
                lefData->lefrFileName);
        fprintf(lefData->lefrLog,
                "WARNING (LEFPARS-%d): %s See file %s at line %d\n",
                msgNum,
                s,
                lefData->lefrFileName,
                lefData->lef_nlines);
      }
    } else {
      if ((lefData->lefrLog = fopen("lefRWarning.log", "a")) == nullptr) {
        printf(
            "WARNING (LEFPARS-2501): Unable to open the file lefRWarning.log "
            "in %s.\n",
            getcwd(nullptr, 64));
        printf("Warning messages will not be printed.\n");
      } else {
        fprintf(lefData->lefrLog,
                "\nWarnings from file: %s\n\n",
                lefData->lefrFileName);
        fprintf(lefData->lefrLog,
                "WARNING (LEFPARS-%d): %s See file %s at line %d\n",
                msgNum,
                s,
                lefData->lefrFileName,
                lefData->lef_nlines);
      }
    }
  }
  lefData->lef_warnings++;
}

void* lefMalloc(size_t lef_size)
{
  void* mallocVar;

  if (lefSettings->MallocFunction) {
    return (*lefSettings->MallocFunction)(lef_size);
  }

  mallocVar = (void*) malloc(lef_size);
  if (!mallocVar) {
    fprintf(stderr, "ERROR (LEFPARS-1009): Not enough memory, stop parsing!\n");
    exit(1);
  }
  return mallocVar;
}

void* lefRealloc(void* name, size_t lef_size)
{
  if (lefSettings->ReallocFunction) {
    return (*lefSettings->ReallocFunction)(name, lef_size);
  }

  return realloc(name, lef_size);
}

void lefFree(void* name)
{
  if (lefSettings->FreeFunction) {
    (*lefSettings->FreeFunction)(name);
  } else {
    free(name);
  }
}

char* lefaddr(const char* in)
{
  return (char*) in;
}

void lefSetNonDefault(const char* nd_name)
{
  lefData->ndName = (char*) malloc(strlen(nd_name) + 1);
  strcpy(lefData->ndName, nd_name);
}

void lefUnsetNonDefault()
{
  lefData->lefNdRule = 0;
  free(lefData->ndName);
}

char* lef_kywd(int num)
{
  char* a;
  switch (num) {
    case K_HISTORY:
      a = lefaddr("HISTORY");
      break;
    case K_ABUT:
      a = lefaddr("ABUT");
      break;
    case K_ABUTMENT:
      a = lefaddr("ABUTMENT");
      break;
    case K_ACTIVE:
      a = lefaddr("ACTIVE");
      break;
    case K_ANALOG:
      a = lefaddr("ANALOG");
      break;
    case K_ANTENNAAREAFACTOR:
      a = lefaddr("ANTENNAAREAFACTOR");
      break;
    case K_ANTENNALENGTHFACTOR:
      a = lefaddr("ANTENNALENGTHFACTOR");
      break;
    case K_ARRAY:
      a = lefaddr("ARRAY");
      break;
    case K_BLOCK:
      a = lefaddr("BLOCK");
      break;
    case K_BOTTOMLEFT:
      a = lefaddr("BOTTOMLEFT");
      break;
    case K_BOTTOMRIGHT:
      a = lefaddr("BOTTOMRIGHT");
      break;
    case K_BUFFER:
      a = lefaddr("BUFFER");
      break;
    case K_BY:
      a = lefaddr("BY");
      break;
    case K_CAPACITANCE:
      a = lefaddr("CAPACITANCE");
      break;
    case K_CAPMULTIPLIER:
      a = lefaddr("CAPMULTIPLIER");
      break;
    case K_CLASS:
      a = lefaddr("CLASS");
      break;
    case K_CLOCK:
      a = lefaddr("CLOCK");
      break;
    case K_COLUMNMAJOR:
      a = lefaddr("COLUMNMAJOR");
      break;
    case K_CORE:
      a = lefaddr("CORE");
      break;
    case K_CORNER:
      a = lefaddr("CORNER");
      break;
    case K_COVER:
      a = lefaddr("COVER");
      break;
    case K_CPERSQDIST:
      a = lefaddr("CPERSQDIST");
      break;
    case K_CURRENT:
      a = lefaddr("CURRENT");
      break;
    case K_CURRENTDEN:
      a = lefaddr("CURRENTDEN");
      break;
    case K_CURRENTSOURCE:
      a = lefaddr("CURRENTSOURCE");
      break;
    case K_CUT:
      a = lefaddr("CUT");
      break;
    case K_DEFAULT:
      a = lefaddr("DEFAULT");
      break;
    case K_DATABASE:
      a = lefaddr("DATABASE");
      break;
    case K_DIELECTRIC:
      a = lefaddr("DIELECTRIC");
      break;
    case K_DIRECTION:
      a = lefaddr("DIRECTION");
      break;
    case K_DO:
      a = lefaddr("DO");
      break;
    case K_EDGECAPACITANCE:
      a = lefaddr("EDGECAPACITANCE");
      break;
    case K_EEQ:
      a = lefaddr("EEQ");
      break;
    case K_END:
      a = lefaddr("END");
      break;
    case K_ENDCAP:
      a = lefaddr("ENDCAP");
      break;
    case K_FALL:
      a = lefaddr("FALL");
      break;
    case K_FALLCS:
      a = lefaddr("FALLCS");
      break;
    case K_FALLT0:
      a = lefaddr("FALLT0");
      break;
    case K_FALLSATT1:
      a = lefaddr("FALLSATT1");
      break;
    case K_FALLRS:
      a = lefaddr("FALLRS");
      break;
    case K_FALLSATCUR:
      a = lefaddr("FALLSATCUR");
      break;
    case K_FALLTHRESH:
      a = lefaddr("FALLTHRESH");
      break;
    case K_FEEDTHRU:
      a = lefaddr("FEEDTHRU");
      break;
    case K_FIXED:
      a = lefaddr("FIXED");
      break;
    case K_FOREIGN:
      a = lefaddr("FOREIGN");
      break;
    case K_FROMPIN:
      a = lefaddr("FROMPIN");
      break;
    case K_FUNCTION:
      a = lefaddr("FUNCTION");
      break;
    case K_GENERATE:
      a = lefaddr("GENERATE");
      break;
    case K_GENERATOR:
      a = lefaddr("GENERATOR");
      break;
    case K_GROUND:
      a = lefaddr("GROUND");
      break;
    case K_HEIGHT:
      a = lefaddr("HEIGHT");
      break;
    case K_HORIZONTAL:
      a = lefaddr("HORIZONTAL");
      break;
    case K_INOUT:
      a = lefaddr("INOUT");
      break;
    case K_INPUT:
      a = lefaddr("INPUT");
      break;
    case K_INPUTNOISEMARGIN:
      a = lefaddr("INPUTNOISEMARGIN");
      break;
    case K_COMPONENTPIN:
      a = lefaddr("COMPONENTPIN");
      break;
    case K_INTRINSIC:
      a = lefaddr("INTRINSIC");
      break;
    case K_INVERT:
      a = lefaddr("INVERT");
      break;
    case K_INVERTER:
      a = lefaddr("INVERTER");
      break;
    case K_IRDROP:
      a = lefaddr("IRDROP");
      break;
    case K_ITERATE:
      a = lefaddr("ITERATE");
      break;
    case K_IV_TABLES:
      a = lefaddr("IV_TABLES");
      break;
    case K_LAYER:
      a = lefaddr("LAYER");
      break;
    case K_LEAKAGE:
      a = lefaddr("LEAKAGE");
      break;
    case K_LEQ:
      a = lefaddr("LEQ");
      break;
    case K_LIBRARY:
      a = lefaddr("LIBRARY");
      break;
    case K_MACRO:
      a = lefaddr("MACRO");
      break;
    case K_MATCH:
      a = lefaddr("MATCH");
      break;
    case K_MAXDELAY:
      a = lefaddr("MAXDELAY");
      break;
    case K_MAXLOAD:
      a = lefaddr("MAXLOAD");
      break;
    case K_METALOVERHANG:
      a = lefaddr("METALOVERHANG");
      break;
    case K_MILLIAMPS:
      a = lefaddr("MILLIAMPS");
      break;
    case K_MILLIWATTS:
      a = lefaddr("MILLIWATTS");
      break;
    case K_MINFEATURE:
      a = lefaddr("MINFEATURE");
      break;
    case K_MUSTJOIN:
      a = lefaddr("MUSTJOIN");
      break;
    case K_NAMEMAPSTRING:
      a = lefaddr("NAMEMAPSTRING");
      break;
    case K_NAMESCASESENSITIVE:
      a = lefaddr("NAMESCASESENSITIVE");
      break;
    case K_NANOSECONDS:
      a = lefaddr("NANOSECONDS");
      break;
    case K_NETS:
      a = lefaddr("NETS");
      break;
    case K_NEW:
      a = lefaddr("NEW");
      break;
    case K_NONDEFAULTRULE:
      a = lefaddr("NONDEFAULTRULE");
      break;
    case K_NONINVERT:
      a = lefaddr("NONINVERT");
      break;
    case K_NONUNATE:
      a = lefaddr("NONUNATE");
      break;
    case K_NOWIREEXTENSIONATPIN:
      a = lefaddr("NOWIREEXTENSIONATPIN");
      break;
    case K_OBS:
      a = lefaddr("OBS");
      break;
    case K_OHMS:
      a = lefaddr("OHMS");
      break;
    case K_OFFSET:
      a = lefaddr("OFFSET");
      break;
    case K_ORIENTATION:
      a = lefaddr("ORIENTATION");
      break;
    case K_ORIGIN:
      a = lefaddr("ORIGIN");
      break;
    case K_OUTPUT:
      a = lefaddr("OUTPUT");
      break;
    case K_OUTPUTNOISEMARGIN:
      a = lefaddr("OUTPUTNOISEMARGIN");
      break;
    case K_OUTPUTRESISTANCE:
      a = lefaddr("OUTPUTRESISTANCE");
      break;
    case K_OVERHANG:
      a = lefaddr("OVERHANG");
      break;
    case K_OVERLAP:
      a = lefaddr("OVERLAP");
      break;
    case K_OFF:
      a = lefaddr("OFF");
      break;
    case K_ON:
      a = lefaddr("ON");
      break;
    case K_OVERLAPS:
      a = lefaddr("OVERLAPS");
      break;
    case K_PAD:
      a = lefaddr("PAD");
      break;
    case K_PATH:
      a = lefaddr("PATH");
      break;
    case K_PATTERN:
      a = lefaddr("PATTERN");
      break;
    case K_PICOFARADS:
      a = lefaddr("PICOFARADS");
      break;
    case K_PIN:
      a = lefaddr("PIN");
      break;
    case K_PITCH:
      a = lefaddr("PITCH");
      break;
    case K_PLACED:
      a = lefaddr("PLACED");
      break;
    case K_POLYGON:
      a = lefaddr("POLYGON");
      break;
    case K_PORT:
      a = lefaddr("PORT");
      break;
    case K_POST:
      a = lefaddr("POST");
      break;
    case K_POWER:
      a = lefaddr("POWER");
      break;
    case K_PRE:
      a = lefaddr("PRE");
      break;
    case K_PULLDOWNRES:
      a = lefaddr("PULLDOWNRES");
      break;
    case K_PWL:
      a = lefaddr("PWL");
      break;
    case K_RECT:
      a = lefaddr("RECT");
      break;
    case K_RESISTANCE:
      a = lefaddr("RESISTANCE");
      break;
    case K_RESISTIVE:
      a = lefaddr("RESISTIVE");
      break;
    case K_RING:
      a = lefaddr("RING");
      break;
    case K_RISE:
      a = lefaddr("RISE");
      break;
    case K_RISECS:
      a = lefaddr("RISECS");
      break;
    case K_RISERS:
      a = lefaddr("RISERS");
      break;
    case K_RISESATCUR:
      a = lefaddr("RISESATCUR");
      break;
    case K_RISETHRESH:
      a = lefaddr("RISETHRESH");
      break;
    case K_RISESATT1:
      a = lefaddr("RISESATT1");
      break;
    case K_RISET0:
      a = lefaddr("RISET0");
      break;
    case K_RISEVOLTAGETHRESHOLD:
      a = lefaddr("RISEVOLTAGETHRESHOLD");
      break;
    case K_FALLVOLTAGETHRESHOLD:
      a = lefaddr("FALLVOLTAGETHRESHOLD");
      break;
    case K_ROUTING:
      a = lefaddr("ROUTING");
      break;
    case K_ROWMAJOR:
      a = lefaddr("ROWMAJOR");
      break;
    case K_RPERSQ:
      a = lefaddr("RPERSQ");
      break;
    case K_SAMENET:
      a = lefaddr("SAMENET");
      break;
    case K_SCANUSE:
      a = lefaddr("SCANUSE");
      break;
    case K_SHAPE:
      a = lefaddr("SHAPE");
      break;
    case K_SHRINKAGE:
      a = lefaddr("SHRINKAGE");
      break;
    case K_SIGNAL:
      a = lefaddr("SIGNAL");
      break;
    case K_SITE:
      a = lefaddr("SITE");
      break;
    case K_SIZE:
      a = lefaddr("SIZE");
      break;
    case K_SOURCE:
      a = lefaddr("SOURCE");
      break;
    case K_SPACER:
      a = lefaddr("SPACER");
      break;
    case K_SPACING:
      a = lefaddr("SPACING");
      break;
    case K_SPECIALNETS:
      a = lefaddr("SPECIALNETS");
      break;
    case K_STACK:
      a = lefaddr("STACK");
      break;
    case K_START:
      a = lefaddr("START");
      break;
    case K_STEP:
      a = lefaddr("STEP");
      break;
    case K_STOP:
      a = lefaddr("STOP");
      break;
    case K_STRUCTURE:
      a = lefaddr("STRUCTURE");
      break;
    case K_SYMMETRY:
      a = lefaddr("SYMMETRY");
      break;
    case K_TABLE:
      a = lefaddr("TABLE");
      break;
    case K_THICKNESS:
      a = lefaddr("THICKNESS");
      break;
    case K_TIEHIGH:
      a = lefaddr("TIEHIGH");
      break;
    case K_TIELOW:
      a = lefaddr("TIELOW");
      break;
    case K_TIEOFFR:
      a = lefaddr("TIEOFFR");
      break;
    case K_TIME:
      a = lefaddr("TIME");
      break;
    case K_TIMING:
      a = lefaddr("TIMING");
      break;
    case K_TO:
      a = lefaddr("TO");
      break;
    case K_TOPIN:
      a = lefaddr("TOPIN");
      break;
    case K_TOPLEFT:
      a = lefaddr("TOPLEFT");
      break;
    case K_TOPRIGHT:
      a = lefaddr("TOPRIGHT");
      break;
    case K_TOPOFSTACKONLY:
      a = lefaddr("TOPOFSTACKONLY");
      break;
    case K_TRISTATE:
      a = lefaddr("TRISTATE");
      break;
    case K_TYPE:
      a = lefaddr("TYPE");
      break;
    case K_UNATENESS:
      a = lefaddr("UNATENESS");
      break;
    case K_UNITS:
      a = lefaddr("UNITS");
      break;
    case K_USE:
      a = lefaddr("USE");
      break;
    case K_VARIABLE:
      a = lefaddr("VARIABLE");
      break;
    case K_VERTICAL:
      a = lefaddr("VERTICAL");
      break;
    case K_VHI:
      a = lefaddr("VHI");
      break;
    case K_VIA:
      a = lefaddr("VIA");
      break;
    case K_VIARULE:
      a = lefaddr("VIARULE");
      break;
    case K_VLO:
      a = lefaddr("VLO");
      break;
    case K_VOLTAGE:
      a = lefaddr("VOLTAGE");
      break;
    case K_VOLTS:
      a = lefaddr("VOLTS");
      break;
    case K_WIDTH:
      a = lefaddr("WIDTH");
      break;
    case K_WIREEXTENSION:
      a = lefaddr("WIREEXTENSION");
      break;
    case K_X:
      a = lefaddr("X");
      break;
    case K_Y:
      a = lefaddr("Y");
      break;
    case K_R90:
      a = lefaddr("R90");
      break;
    case T_STRING:
      a = lefaddr("T_STRING");
      break;
    case QSTRING:
      a = lefaddr("QSTRING");
      break;
    case NUMBER:
      a = lefaddr("NUMBER");
      break;
    case K_N:
      a = lefaddr("N");
      break;
    case K_S:
      a = lefaddr("S");
      break;
    case K_E:
      a = lefaddr("E");
      break;
    case K_W:
      a = lefaddr("W");
      break;
    case K_FN:
      a = lefaddr("FN");
      break;
    case K_FS:
      a = lefaddr("FS");
      break;
    case K_FE:
      a = lefaddr("FE");
      break;
    case K_FW:
      a = lefaddr("FW");
      break;
    case K_USER:
      a = lefaddr("USER");
      break;
    case K_MASTERSLICE:
      a = lefaddr("MASTERSLICE");
      break;
    case K_ENDMACRO:
      a = lefaddr("ENDMACRO");
      break;
    case K_ENDMACROPIN:
      a = lefaddr("ENDMACROPIN");
      break;
    case K_ENDVIARULE:
      a = lefaddr("ENDVIARULE");
      break;
    case K_ENDVIA:
      a = lefaddr("ENDVIA");
      break;
    case K_ENDLAYER:
      a = lefaddr("ENDLAYER");
      break;
    case K_ENDSITE:
      a = lefaddr("ENDSITE");
      break;
    case K_CANPLACE:
      a = lefaddr("CANPLACE");
      break;
    case K_CANNOTOCCUPY:
      a = lefaddr("CANNOTOCCUPY");
      break;
    case K_TRACKS:
      a = lefaddr("TRACKS");
      break;
    case K_FLOORPLAN:
      a = lefaddr("FLOORPLAN");
      break;
    case K_GCELLGRID:
      a = lefaddr("GCELLGRID");
      break;
    case K_DEFAULTCAP:
      a = lefaddr("DEFAULTCAP");
      break;
    case K_MINPINS:
      a = lefaddr("MINPINS");
      break;
    case K_WIRECAP:
      a = lefaddr("WIRECAP");
      break;
    case K_STABLE:
      a = lefaddr("STABLE");
      break;
    case K_SETUP:
      a = lefaddr("SETUP");
      break;
    case K_HOLD:
      a = lefaddr("HOLD");
      break;
    case K_DEFINE:
      a = lefaddr("DEFINE");
      break;
    case K_DEFINES:
      a = lefaddr("DEFINES");
      break;
    case K_DEFINEB:
      a = lefaddr("DEFINEB");
      break;
    case K_IF:
      a = lefaddr("IF");
      break;
    case K_THEN:
      a = lefaddr("THEN");
      break;
    case K_ELSE:
      a = lefaddr("ELSE");
      break;
    case K_FALSE:
      a = lefaddr("FALSE");
      break;
    case K_TRUE:
      a = lefaddr("TRUE");
      break;
    case K_EQ:
      a = lefaddr("EQ");
      break;
    case K_NE:
      a = lefaddr("NE");
      break;
    case K_LE:
      a = lefaddr("LE");
      break;
    case K_LT:
      a = lefaddr("LT");
      break;
    case K_GE:
      a = lefaddr("GE");
      break;
    case K_GT:
      a = lefaddr("GT");
      break;
    case K_OR:
      a = lefaddr("OR");
      break;
    case K_AND:
      a = lefaddr("AND");
      break;
    case K_NOT:
      a = lefaddr("NOT");
      break;
    case K_DELAY:
      a = lefaddr("DELAY");
      break;
    case K_TABLEDIMENSION:
      a = lefaddr("TABLEDIMENSION");
      break;
    case K_TABLEAXIS:
      a = lefaddr("TABLEAXIS");
      break;
    case K_TABLEENTRIES:
      a = lefaddr("TABLEENTRIES");
      break;
    case K_TRANSITIONTIME:
      a = lefaddr("TRANSITIONTIME");
      break;
    case K_EXTENSION:
      a = lefaddr("EXTENSION");
      break;
    case K_PROPDEF:
      a = lefaddr("PROPDEF");
      break;
    case K_STRING:
      a = lefaddr("STRING");
      break;
    case K_INTEGER:
      a = lefaddr("INTEGER");
      break;
    case K_REAL:
      a = lefaddr("REAL");
      break;
    case K_RANGE:
      a = lefaddr("RANGE");
      break;
    case K_PROPERTY:
      a = lefaddr("PROPERTY");
      break;
    case K_VIRTUAL:
      a = lefaddr("VIRTUAL");
      break;
    case K_BUSBITCHARS:
      a = lefaddr("BUSBITCHARS");
      break;
    case K_VERSION:
      a = lefaddr("VERSION");
      break;
    case K_BEGINEXT:
      a = lefaddr("BEGINEXT");
      break;
    case K_ENDEXT:
      a = lefaddr("ENDEXT");
      break;
    case K_UNIVERSALNOISEMARGIN:
      a = lefaddr("UNIVERSALNOISEMARGIN");
      break;
    case K_EDGERATETHRESHOLD1:
      a = lefaddr("EDGERATETHRESHOLD1");
      break;
    case K_CORRECTIONTABLE:
      a = lefaddr("CORRECTIONTABLE");
      break;
    case K_EDGERATESCALEFACTOR:
      a = lefaddr("EDGERATESCALEFACTOR");
      break;
    case K_EDGERATETHRESHOLD2:
      a = lefaddr("EDGERATETHRESHOLD2");
      break;
    case K_VICTIMNOISE:
      a = lefaddr("VICTIMNOISE");
      break;
    case K_NOISETABLE:
      a = lefaddr("NOISETABLE");
      break;
    case K_EDGERATE:
      a = lefaddr("EDGERATE");
      break;
    case K_VICTIMLENGTH:
      a = lefaddr("VICTIMLENGTH");
      break;
    case K_CORRECTIONFACTOR:
      a = lefaddr("CORRECTIONFACTOR");
      break;
    case K_OUTPUTPINANTENNASIZE:
      a = lefaddr("OUTPUTPINANTENNASIZE");
      break;
    case K_INPUTPINANTENNASIZE:
      a = lefaddr("INPUTPINANTENNASIZE");
      break;
    case K_INOUTPINANTENNASIZE:
      a = lefaddr("INOUTPINANTENNASIZE");
      break;
    case K_TAPERRULE:
      a = lefaddr("TAPERRULE");
      break;
    case K_DIVIDERCHAR:
      a = lefaddr("DIVIDERCHAR");
      break;
    case K_ANTENNASIZE:
      a = lefaddr("ANTENNASIZE");
      break;
    case K_ANTENNAMETALAREA:
      a = lefaddr("ANTENNAMETALAREA");
      break;
    case K_ANTENNAMETALLENGTH:
      a = lefaddr("ANTENNAMETALLENGTH");
      break;
    case K_RISESLEWLIMIT:
      a = lefaddr("RISESLEWLIMIT");
      break;
    case K_FALLSLEWLIMIT:
      a = lefaddr("FALLSLEWLIMIT");
      break;
    case K_MESSAGE:
      a = lefaddr("MESSAGE");
      break;
    case K_CREATEFILE:
      a = lefaddr("CREATEFILE");
      break;
    case K_OPENFILE:
      a = lefaddr("OPENFILE");
      break;
    case K_CLOSEFILE:
      a = lefaddr("CLOSEFILE");
      break;
    case K_WARNING:
      a = lefaddr("WARNING");
      break;
    case K_ERROR:
      a = lefaddr("ERROR");
      break;
    case K_FATALERROR:
      a = lefaddr("FATALERROR");
      break;
    case IF:
      a = lefaddr("IF");
      break;
    case LNOT:
      a = lefaddr("LNOT");
      break;
    case UMINUS:
      a = lefaddr("UMINUS");
      break;

    default:
      a = lefaddr("bogus");
  }
  return a;
}

END_LEF_PARSER_NAMESPACE
